package fractal;

import java.awt.*;

/**
 * Created by IntelliJ IDEA.
 * User: ilya
 * Date: 25.09.11
 * Time: 1:38
 */
public class MandelbrotFractal implements Fractal {

    private static final int maxIterations = 1000;
    private static final double R = 2 << 16;
    private static final int[] palette = new int[1000];

    public MandelbrotFractal() {
        for (int i = 0; i < palette.length; i++) {
            int h = (i + 70) % 100;
            int s = i / 100;
            palette[i] = Color.HSBtoRGB(h / 100f, s / 20f + 0.5f, 1f);
        }
    }

    public int isIn(double x, double y) {
        double zRe = 0;
        double zIm = 0;

        for (int it = 0; it < maxIterations; it++) {
            double zNewRe = x + zRe * zRe - zIm * zIm;
            double zNewIm = y + 2 * zRe * zIm;

            double d = zNewRe * zNewRe + zNewIm * zNewIm;

            if (d > R * R)
                return iteration2color(it + 1 - Math.log(Math.log(d) / 2 / Math.log(2)) / Math.log(2));

            zRe = zNewRe;
            zIm = zNewIm;
        }

        return iteration2color(maxIterations);
    }

    private int iteration2color(double iteration) {
        if (iteration >= palette.length - 1)
            return palette[palette.length - 1];

        if (iteration < 0)
            iteration = 0;

        int it1 = (int) Math.floor(iteration);

        double it2 = iteration - it1;

        int c1 = palette[it1];
        int c2 = palette[it1 + 1];

        return (interpolate(c1 >> 16, c2 >> 16, it2) << 16)
                + (interpolate(c1 >> 8 & 0xFF, c2 >> 8 & 0xFF, it2) << 8)
                + interpolate(c1 & 0xFF, c2 & 0xFF, it2);
    }

    private int interpolate(int a, int b, double ratio) {
        return (int) Math.round(a + (b - a) * ratio);
    }
}
